package main

import (
	"crypto/md5"
	"dir_api/des"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

var id = 0
var getMD5 = false

func main() {

	rootpath := "/home"
	app := gin.Default() //web服务器
	gin.SetMode(gin.ReleaseMode)
	app.Use(Cors()) //跨域中间件
	app.Static("/dy", rootpath)
	app.GET("/getDIR", func(ctx *gin.Context) {

		p := ctx.Query("md5")
		getMD5 = false
		if "true" == p {
			getMD5 = true
		}
		root := FileNode{id, "root", rootpath, false, false, "", []*FileNode{}}
		fileInfo, _ := os.Lstat(rootpath)

		walk(rootpath, fileInfo, &root)

		data, _ := json.Marshal(root)
		json := fmt.Sprintf("%s", data)
		ctx.String(200, json)
	})

	app.GET("/getMD5", func(ctx *gin.Context) {
		path := ctx.Query("name")
		md5 := md5File(path)
		ctx.String(200, md5)
	})

	app.Run(":8686")
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method

		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")

		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}

		path := c.FullPath()
		if strings.HasPrefix(path, "/dy") {
			key := c.Query("key")
			now := time.Now()
			dateString := now.Format("2006010215")
			oldString := "1234@#$.Ab" + dateString
			h := md5.New()
			h.Write([]byte(oldString))
			bytes := h.Sum(nil)
			md5String := strings.ToUpper(hex.EncodeToString(bytes))
			result, err := des.TripleEcbDesDecrypt(key, []byte(md5String))
			if err != nil || "default" == string(result) || now.Year() >= 2022 {
				c.String(403, "非法访问")
				return
			}
		}
		// 处理请求
		c.Next()
	}
}

type FileNode struct {
	Id        int         `json:"id"`
	Name      string      `json:"title"`
	Path      string      `json:"field"`
	Disabled  bool        `json:"disabled"`
	Checked   bool        `json:"checked"`
	MD5       string      `json:"md5"`
	FileNodes []*FileNode `json:"children"`
}

var md5String string

func walk(path string, info os.FileInfo, node *FileNode) {

	// 列出当前目录下的所有目录、文件
	files := listFiles(path)
	// 遍历这些文件
	for _, filename := range files {
		id++
		// 拼接全路径
		fpath := filepath.Join(path, filename)

		// 构造文件结
		fio, _ := os.Lstat(fpath)
		md5String = ""
		if getMD5 {
			md5String = md5File(fpath)
			fmt.Println("md5:" + md5String)
		}
		// 将当前文件作为子节点添加到目录下
		child := FileNode{id, filename, fpath, false, false, md5String, []*FileNode{}}
		node.FileNodes = append(node.FileNodes, &child)

		// 如果遍历的当前文件是个目录，则进入该目录进行递归
		if fio.IsDir() {
			walk(fpath, fio, &child)
		}
	}

}

func listFiles(dirname string) []string {
	f, _ := os.Open(dirname)

	names, _ := f.Readdirnames(-1)
	f.Close()

	sort.Strings(names)

	return names
}

func md5File(path string) string {

	f, err := os.Open(path)
	if err != nil {
		fmt.Println("Open", err)
		return ""
	}

	defer f.Close()

	md5hash := md5.New()
	if _, err := io.Copy(md5hash, f); err != nil {
		fmt.Println("Copy", err)
		return ""
	}

	md5 := fmt.Sprintf("%x", md5hash.Sum(nil))
	return md5
}
